use std::sync::LazyLock;

use tokio::sync::RwLock;

use anyhow::anyhow;
use salvo::Depot;

use crate::config::handler_config::{AdminType, Claims};

pub mod login_service;
pub mod menu_service;
pub mod org_service;
pub mod role_service;

pub mod user_service;

pub static CLAIMS: &str = "claims";
pub static DATE_FORMAT: &str = "%Y-%m-%d %H:%M:%S";

pub static USER_CONTEXT_HOLDER: LazyLock<RwLock<ContextHolder>> =
    LazyLock::new(|| RwLock::new(ContextHolder::default()));

#[derive(Debug, Default)]
pub struct ContextHolder {
    pub org_id: Option<i64>,
    pub user_id: Option<i64>,
    pub user_name: Option<String>,
    pub admin: AdminType,
}

impl ContextHolder {
    pub async fn builder(depot: &mut Depot) -> anyhow::Result<()> {
        if let Ok(claims) = depot.get::<Claims>(CLAIMS) {
            let mut context_holder = USER_CONTEXT_HOLDER.write().await;
            *context_holder = ContextHolder {
                org_id: claims.org_id,
                user_id: claims.user_id,
                user_name: claims.user_name.clone(),
                admin: claims.admin,
            };

            drop(context_holder);
        } else {
            return Err(anyhow!("claims not exits"));
        }
        Ok(())
    }
}

pub async fn get_login_user(depot: &mut Depot) -> anyhow::Result<&Claims> {
    let claims = depot.get::<Claims>(CLAIMS);
    match claims {
        Ok(c) => Ok(c),
        Err(e) => Err(anyhow!("user error {:?}", e)),
    }
}

pub async fn get_login_org(depot: &mut Depot) -> anyhow::Result<Option<i64>> {
    let claims = get_login_user(depot).await?;
    Ok(claims.org_id)
}

pub async fn get_login_user_role(depot: &mut Depot) -> anyhow::Result<Option<i64>> {
    let claims = get_login_user(depot).await?;
    Ok(claims.role_id)
}
